﻿using Linguist.Acoustic;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Runtime.Caching;
using Util;
using Common;

namespace Linguist.Flat
{
    
    /// <summary>
    /// A class that represents a set of units used as a context
    /// </summary>
    public class UnitContext
    {

        public static UnitContext EMPTY = new UnitContext(Unit.EMPTY_ARRAY);

        //private static Cache<UnitContext> unitContextCache = new Cache<UnitContext>();
        private IUnit[] context = null;
        private int _hashCode = 12;

        public static UnitContext SILENCE = new UnitContext(new Unit[] { UnitManager.SILENCE });

 

        /// <summary>
        /// Creates a UnitContext for the given context. This constructor is not directly accessible, use the factory method
        /// instead.
        /// </summary>
        /// <param name="context">context the context to wrap with this UnitContext</param>
        private UnitContext(IUnit[] context)
        {
            //unitContextCache.cache(EMPTY);
            //unitContextCache.cache(SILENCE);
            this.context = context;
            _hashCode = 12;
            for (int i = 0; i < context.Length; i++)
            {
                if (context[i]!=null)
                    _hashCode += context[i].getName().GetHashCode() * ((i + 1) * 34);
            }
           
        }


        /// <summary>
        /// Gets the unit context for the given units. There is a single unit context for each unit combination.
        /// </summary>
        /// <param name="units">the units of interest</param>
        /// <returns>the unit context.</returns>
        public static UnitContext get(IUnit[] units)
        {
            UnitContext newUC = new UnitContext(units);
            //UnitContext cachedUC = unitContextCache.cache(newUC);
            //return cachedUC == null ? newUC : cachedUC;
            return newUC;
        }

        /// <summary>
        /// Retrieves the units for this context
        /// </summary>
        /// <returns>the units associated with this context</returns>
        public IUnit[] getUnits()
        {
            return context;
        }

        /// <summary>
        /// Determines if the given object is equal to this UnitContext
        /// </summary>
        /// <param name="o">the object to compare to</param>
        /// <returns><code>true</code> if the objects are equal</returns>
        override public Boolean Equals(Object o)
        {
            if (this == o)
            {
                return true;
            }
            else if (o is UnitContext)
            {
                UnitContext other = (UnitContext)o;
                if (this.context.Length != other.context.Length)
                {
                    return false;
                }
                else
                {
                    for (int i = 0; i < this.context.Length; i++)
                    {
                        if (this.context[i] != other.context[i])
                        {
                            return false;
                        }
                    }
                    return true;
                }
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// Returns a hashcode for this object
        /// </summary>
        /// <returns>the hashCode</returns>
        public int hashCode()
        {
            return _hashCode;
        }


        /// <summary>
        /// Dumps information about the total number of UnitContext objects
        /// </summary>
        public static void dumpInfo()
        {
            Trace.WriteLine("Total number of UnitContexts : ");
                //+ unitContextCache.getMisses().ToString() 
                //+ " folded: " + unitContextCache.getHits().ToString());
        }


        /// <summary>
        /// Returns a string representation of this object
        /// </summary>
        /// <returns>string representation</returns>
        override public String ToString()
        {
            return LeftRightContext.getContextName(context);
        }
        

    }

}
